﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Collections;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Data.Odbc;
using System.Data.OleDb;
using System.Configuration;
using System.IO;
using System.Xml;

namespace PATBController
{
    /*
     * Manages Runs
    */

    public class RunsManagerClass
    {
        public TestMachineManagerClass TestMachineManager { get; set; }
        public Dictionary<int, Run> ScheduledRuns;
        public OrderedDictionary Tests;
        public List<int> ActiveTests;
        public Dictionary<int, TestSequence> ActiveSequentialTestSets;
        public List<int> TestsPendingPrep;
        private int TestsExecutionCompleted = 0;
        private int TestsResultsPending = 0;
        private int TestsConcluded = 0;
        private int TestsFromPriorRuns = 0;
        private int TestsError = 0;
        private DateTime EngineRunStarted = DateTime.Now;
        private bool PendingCleanExit = false;

        public RunsManagerClass()
        {
            TestMachineManager = new TestMachineManagerClass();
            ScheduledRuns = new Dictionary<int, Run>();
            Tests = new OrderedDictionary();
            ActiveTests = new List<int>();
            TestsPendingPrep = new List<int>();
            ActiveSequentialTestSets = new Dictionary<int, TestSequence>();
            ResetTestProcInfoFile(0);

            Refresh(0);
        }
        public void ReportStatus(int iLogIndent)
        {
            TimeSpan tsRunTime = DateTime.Now.Subtract(EngineRunStarted);
            double iRunTimeDays = Math.Floor(tsRunTime.TotalDays);
            int iRunTimeHrs = tsRunTime.Hours;
            int iRunTimeMins = tsRunTime.Minutes;

            Logger.Log(iLogIndent, "RunsManager", "~~ "
                + "Active Runs: " + ScheduledRuns.Count.ToString()
                + "; TestCount: " + Tests.Count.ToString()
                + "; TCPriorRuns: " + TestsFromPriorRuns.ToString()
                + "; RunTime: " + iRunTimeDays.ToString("N0") + "d "
                                + iRunTimeHrs.ToString("D2") + "h " 
                                + iRunTimeMins.ToString("D2") + "m"
                );
            Logger.Log(iLogIndent, "RunsManager", "~~ Tests: "
                + "Pend Prep: " + TestsPendingPrep.Count.ToString()
                + "; Inprog: " + ActiveTests.Count.ToString()
                + "; SeqTS: " + ActiveSequentialTestSets.Count.ToString()
                + "; Pend Results: " + TestsResultsPending.ToString()
                + "; Done: " + TestsConcluded.ToString()
                + "; Error: " + TestsError.ToString()
                );
            Logger.Log(iLogIndent, "RunsManager", "~~ Machines: "
                + "Count: " + TestMachineManager.GetTestMachineActiveCount().ToString()
                + "; InUse: " + TestMachineManager.GetTestMachineInUseCount().ToString()
                + "; MaxVMConn: " + TestMachineManager.GetVirtualServerMaxConnectionCount().ToString()
                + "; InUseVMConn: " + TestMachineManager.GetVirtualServerActiveConnectionCount().ToString()
                );
            if (PendingCleanExit)
                Logger.Log(iLogIndent, "RunsManager", "~~ ** Pending Clean Exit");

        }
        public bool CheckCleanExitStatus()
        {
            PendingCleanExit = true;
            return ((TestsPendingPrep.Count + ActiveTests.Count + TestsResultsPending) == 0);
        }
        public void Refresh(int iLogIndent)
        {
            List<int> lsIDs = new List<int>();
            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                // check if any are complete
                if(ScheduledRuns.Count > 0)
                {
                    foreach(Run oRun in ScheduledRuns.Values)
                    {
                        if (oRun.InProgress)
                            objATBDB.CheckRunsComplete(oRun.Key);
                    }
                }

                DataTable dtList;
                dtList = objATBDB.GetRunsList();

                for (int iIndex = 0; iIndex < dtList.Rows.Count; iIndex++)
                {
                    int iKey = int.Parse(dtList.Rows[iIndex]["RunsID"].ToString());
                    if (!ScheduledRuns.ContainsKey(iKey))
                    {
                        // populate the run
                        Run oRun = new Run(
                            iKey,
                            dtList.Rows[iIndex]["RunName"].ToString(),
                            DateTime.Parse(dtList.Rows[iIndex]["Scheduled"].ToString()),
                            dtList.Rows[iIndex]["Identifier"].ToString(),
                            (dtList.Rows[iIndex]["InProgress"].ToString().ToLower() == "true")
                            );
                        ScheduledRuns.Add(iKey, oRun);
                        Logger.Log(iLogIndent, "RunsManager", "-Added run RunsID==" + oRun.Key.ToString() + "; Name==" + oRun.Name);

                        if (oRun.InProgress)
                            StartRun_GetTests(oRun.Key, iLogIndent+1);
                    }
                    lsIDs.Add(iKey);
                }
            }
            // check for orphans
            List<int> liRunsKeysCopy = ScheduledRuns.Keys.ToList<int>();
            foreach (int iRunKey in liRunsKeysCopy)
            {
                if (!lsIDs.Contains(iRunKey))
                {
                    Logger.Log(iLogIndent, "RunsManager", "-Runs orphan found, removing; RunsID==" + iRunKey.ToString() + "; Name==" + ScheduledRuns[iRunKey].Name);
                    ScheduledRuns.Remove(iRunKey);
                    // Remove tests associated with the run
                    String[] lsTestKeys = new String[Tests.Count];
                    Tests.Keys.CopyTo(lsTestKeys, 0);
                    foreach(string sTestKey in lsTestKeys)
                    {
                        DefTestCase oTest = (DefTestCase)Tests[sTestKey];
                        if (oTest.RunKey == iRunKey)
                        {
                            TestsFromPriorRuns++;
                            Tests.Remove(sTestKey);
                        }
                    }
                }
            }
            TestMachineManager.Refresh(iLogIndent + 1);

            // check active test set sequences
            List<TestSequence> listActiveTestSequenceCopy = ActiveSequentialTestSets.Values.ToList<TestSequence>();
            foreach (TestSequence oSeq in listActiveTestSequenceCopy)
            {
                if (oSeq.AllTestsCompleted())
                    ActiveSequentialTestSets.Remove(oSeq.TestSetKey);
            }

            // update counts
            TestsConcluded = 0;
            TestsExecutionCompleted = 0;
            TestsResultsPending = 0;
            foreach(DefTestCase oTest in Tests.Values)
            {
                if(oTest.Completed)
                {
                    TestsExecutionCompleted++;
                    if (oTest.ResultsPosted)
                        TestsConcluded++;
                    else
                        TestsResultsPending++;
                }
            }
        }
        public void InitVirtualMachines(int iLogIndent)
        {
            TestMachineManager.InitVirtualMachines(iLogIndent);
        }
        public void CheckStartRuns(int iLogIndent)
        {
            foreach (Run oRun in ScheduledRuns.Values)
            {
                if (!oRun.InProgress)
                {
                    if (oRun.Schedule <= DateTime.Now)
                    {
                        StartRun(oRun, iLogIndent + 1);
                    }
                }
            }
        }
        public void StartRun(Run oRun, int iLogIndent)
        {
            Logger.Log(iLogIndent, "RunsManager", "-Starting New Run: " + oRun.Name);
            oRun.InProgress = true;
            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                objATBDB.StartRun(oRun.Key);
            }
            StartRun_GetTests(oRun.Key, iLogIndent + 1);
        }
        public void CheckStartTest(int iLogIndent)
        {
            // next check any individual tests ready to start
            int iTestToStartID = GetNextAvailableTest(iLogIndent + 1);
            if (iTestToStartID != -1)
            {
                StartTest(iTestToStartID, iLogIndent + 1);
                return;
            }
        }
        public void CheckRunningTests(int iLogIndent)
        {
            // check active tests
            List<int> liActiveTestsCopy = ActiveTests.ToList<int>();
            foreach (int iTestID in liActiveTestsCopy)
            {
                if (CheckRunningTest((DefTestCase)Tests[iTestID.ToString("D8")], iLogIndent + 1))
                {
                    if(ActiveTests.Contains(iTestID))
                        ActiveTests.Remove(iTestID);
                }
            }
            // check pending tests
            if (TestsPendingPrep.Count > 0)
            {
                List<int> TestsPendingPrep_Copy = TestsPendingPrep.ToList<int>();
                foreach (int iTestID in TestsPendingPrep_Copy)
                {
                    DefTestCase oTest = (DefTestCase)Tests[iTestID.ToString("D8")];
                    if (TestMachineManager.CheckPendingReady(oTest.AsssignedTestMachine))
                        StartTest_Finalize(iTestID, iLogIndent + 1);
                }
            }
        }
        public void CheckPostResults(int iLogIndent)
        {
            if(TestsResultsPending > 0)
            {
                foreach (DefTestCase oTest in Tests.Values)
                {
                    // don't process any of the sequence until all are complete
                    if (ActiveSequentialTestSets.ContainsKey(oTest.TestSetKey))
                        continue;

                    if (oTest.Completed)
                    {
                        if (!oTest.ResultsPosted)
                        {
                            PostResult(oTest, iLogIndent + 1);
                            break;
                        }
                    }
                }
            }
        }
        private void StartRun_GetTests(int iRunKey, int iLogIndent)
        {
            int iDefaultMaxWaitTime = int.Parse(ConfigurationManager.AppSettings["TestExecutionTimeoutMins"]);

            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                // Populate Test Cases
                DataTable dtList;
                dtList = objATBDB.GetTestListForRun(iRunKey);
                for (int iIndex = 0; iIndex < dtList.Rows.Count; iIndex++)
                {
                    // get the key
                    int iKey = int.Parse(dtList.Rows[iIndex]["Key"].ToString());
                    // preprocess complex fields
                    // Test machine list is returned as a comma delimited string
                    string sVal = dtList.Rows[iIndex]["TestMachineGroup"].ToString();
                    List<int> liTestMachineGroup = null;
                    if (sVal.ToLower() != "null" && sVal.Trim().Length > 0)
                    {
                        liTestMachineGroup = new List<int>();
                        List<string> lsTestMachineGroup = sVal.Split(',').ToList<string>();
                        foreach (string sTestMachine in lsTestMachineGroup)
                            liTestMachineGroup.Add(int.Parse(sTestMachine));
                    }
                    // Test data might be null
                    int iTestDataSetDataKey = -1;
                    sVal = dtList.Rows[iIndex]["TestDataSetDataKey"].ToString();
                    if (sVal.ToLower() != "null" && sVal.Trim().Length > 0)
                        int.TryParse(sVal, out iTestDataSetDataKey);
                    int iMaxExecutionTimeMins = iDefaultMaxWaitTime;
                    sVal = dtList.Rows[iIndex]["MaxExecutionTimeMins"].ToString();
                    if (sVal.ToLower() != "null" && sVal.Trim().Length > 0)
                        int.TryParse(sVal, out iMaxExecutionTimeMins);
                    // booleans might be null
                    sVal = dtList.Rows[iIndex]["InProgress"].ToString();
                    bool bInProgress = (sVal.ToLower() == "true");
                    sVal = dtList.Rows[iIndex]["Completed"].ToString();
                    bool bCompleted = (sVal.ToLower() == "true");
                    sVal = dtList.Rows[iIndex]["ResultsPosted"].ToString();
                    bool bResultsPosted = (sVal.ToLower() == "true");

                    if (!(liTestMachineGroup == null))
                    {
                        DefTestCase oTest = new DefTestCase
                        {
                            Key = iKey,
                            Guid = dtList.Rows[iIndex]["Guid"].ToString(),
                            RunKey = int.Parse(dtList.Rows[iIndex]["RunKey"].ToString()),
                            RunGuid = dtList.Rows[iIndex]["RunGuid"].ToString(),
                            DefRunKey = int.Parse(dtList.Rows[iIndex]["DefRunKey"].ToString()),
                            TestSetKey = int.Parse(dtList.Rows[iIndex]["TestSetKey"].ToString()),
                            TestSetGuid = dtList.Rows[iIndex]["TestSetGuid"].ToString(),
                            DefTestCaseID = int.Parse(dtList.Rows[iIndex]["DefTestCaseID"].ToString()),
                            TestCaseName = dtList.Rows[iIndex]["TestCaseName"].ToString(),
                            TestQCID = dtList.Rows[iIndex]["TestQCID"].ToString(),
                            TestCaseRevision = dtList.Rows[iIndex]["TestCaseRevision"].ToString(),
                            Order = double.Parse(dtList.Rows[iIndex]["Order"].ToString()),
                            MaxExecutionTimeMins = iMaxExecutionTimeMins,
                            TestMachineGroup = liTestMachineGroup,
                            ExecutionOrder = DefTestCase.ParseExecutionOrder(dtList.Rows[iIndex]["ExecutionOrder"].ToString()),
                            MachineOp = DefTestCase.ParseMachineOp(dtList.Rows[iIndex]["MachineOp"].ToString()),
                            DefRunDataID = int.Parse(dtList.Rows[iIndex]["DefRunDataID"].ToString()),
                            TestDataSetDataKey = iTestDataSetDataKey,
                            InProgress = bInProgress,
                            Completed = bCompleted,
                            ResultsPosted = bResultsPosted,
                            AsssignedTestMachine = -1,
                            ClientPid = null
                        };

                        Tests.Add(iKey.ToString("D8"), oTest);
                        if (oTest.InProgress && !oTest.Completed)
                            ActiveTests.Add(iKey);
                        if (oTest.Completed)
                        {
                            TestsExecutionCompleted++;
                            if (!oTest.ResultsPosted)
                                TestsResultsPending++;
                            else
                                TestsConcluded++;
                        }
                    }
                }
            }

        }
        public int GetNextAvailableTest(int iLogIndent)
        {
            foreach (DefTestCase oTest in Tests.Values)
            {
                // Is the test in progress?
                if (!oTest.InProgress)
                    if (!TestsPendingPrep.Contains(oTest.Key))
                        if(!ActiveSequentialTestSets.ContainsKey(oTest.TestSetKey))
                            // Is there a test machine available?
                            if (TestMachineManager.CheckAvailable(oTest.TestMachineGroup))
                                return (oTest.Key);
            }
            return (-1);
        }
        public void StartTest(int iTestID, int iLogIndent)
        {
            StartTest(iTestID, false, iLogIndent + 1);
        }
        public void StartTest_Finalize(int iTestID, int iLogIndent)
        {
            StartTest(iTestID, true, iLogIndent + 1);
        }
        public void StartTest(int iTestID, bool bFinalize, int iLogIndent)
        {
            DefTestCase oTest = (DefTestCase)Tests[iTestID.ToString("D8")];
            int iTestMachineID;
            DirectoryInfo dirTarget;

            if (bFinalize)
            {
                Logger.Log(iLogIndent, "RunsManager", "-Finalizing new test: ID==" + oTest.Key.ToString() + " ;Name==" + oTest.TestCaseName);
                iTestMachineID = oTest.AsssignedTestMachine;
                dirTarget = new DirectoryInfo(oTest.ResultsPath);
            }
            else
            {
                Logger.Log(iLogIndent, "RunsManager", "-Starting new test: ID==" + oTest.Key.ToString() + " ;Name==" + oTest.TestCaseName);

                // check if it should be part of a sequence
                iTestMachineID = TestMachineManager.GetAvailable(oTest.TestMachineGroup);
                if (iTestMachineID == -1)
                    return;

                // build out the folder info
                dirTarget = StartTest_BuildResultsPath(oTest, iLogIndent + 1);
                oTest.ResultsPath = dirTarget.ToString();

                if ((oTest.ExecutionOrder == enumExecutionOrder.Sequential
                && oTest.MachineOp == enumMachineOp.RestoreInitiallyForSet))
                {
                    // build sequence
                    DefTestCase[] TestList = new DefTestCase[Tests.Count];
                    Tests.Values.CopyTo(TestList, 0);
                    TestSequence oTestSeq = new TestSequence(oTest, TestList);
                    ActiveSequentialTestSets.Add(oTest.TestSetKey, oTestSeq);
                }
            }

            Logger.Log(iLogIndent, "RunsManager", "-Using test machine: ID==" + iTestMachineID.ToString());

            if (bFinalize)
            {
                int iResult = TestMachineManager.SetInUse_Finalize(iTestMachineID, oTest, iLogIndent + 1);
                if(iResult == -1)
                {
                    Logger.Log(iLogIndent, "RunsManager", "-ERROR: Cannot set active test machine: ID==" + iTestMachineID.ToString());
                    TestsPendingPrep.Remove(iTestID);
                    if (ActiveSequentialTestSets.ContainsKey(oTest.TestSetKey))
                        ActiveSequentialTestSets.Remove(oTest.TestSetKey);
                    return;
                }
                if (iResult == 0)
                    return;

                TestsPendingPrep.Remove(iTestID);
            }
            else
            {

                if (!TestMachineManager.SetUse(iTestMachineID, oTest, true, iLogIndent + 1))
                {
                    Logger.Log(iLogIndent, "RunsManager", "-ERROR: Cannot set active test machine: ID==" + iTestMachineID.ToString());
                    return;
                }

                if(TestMachineManager.IsVirtual(iTestMachineID))
                {
                    TestsPendingPrep.Add(iTestID);
                    return;
                }
            }
            // write the xml input file
            Logger.Log(iLogIndent, "RunsManager", "-Writing input file");
            if (!StartTest_WriteInputFile(oTest, dirTarget, iLogIndent + 1))
            {
                Logger.Log(iLogIndent, "RunsManager", "-ERROR: Problem when writing input file");
                return;
            }

            Logger.Log(iLogIndent, "RunsManager", "-Launching process");
            StartTest_LaunchClient(oTest, iLogIndent + 1);

            Logger.Log(iLogIndent, "RunsManager", "-Setting InProgress state in DB");

            if (ActiveSequentialTestSets.ContainsKey(oTest.TestSetKey))
            {
                using (ATBSchemaDB objATBDB = new ATBSchemaDB())
                {
                    foreach (DefTestCase oTestInSeq in ActiveSequentialTestSets[oTest.TestSetKey].TestCaseSeq.Values)
                    {
                        objATBDB.TestIndicateStart(oTestInSeq.Key, oTestInSeq.RunKey);

                        oTestInSeq.InProgress = true;
                        oTestInSeq.Tries++;
                        oTestInSeq.AssignedIp = oTest.AssignedIp;
                        oTestInSeq.ClientPid = ActiveSequentialTestSets[oTest.TestSetKey].ClientPid;
                        ActiveTests.Add(oTestInSeq.Key);
                    }
                }
                Logger.Log(iLogIndent, "RunsManager", 
                    "-Added test sequence (" 
                    + ActiveSequentialTestSets[oTest.TestSetKey].Count.ToString()
                    + " tests) to active tests: New count==" 
                    + ActiveTests.Count.ToString());
            }
            else
            {
                using (ATBSchemaDB objATBDB = new ATBSchemaDB())
                {
                    objATBDB.TestIndicateStart(oTest.Key, oTest.RunKey);
                }
                oTest.InProgress = true;
                oTest.Tries++;
                ActiveTests.Add(iTestID);
                Logger.Log(iLogIndent, "RunsManager", 
                    "-Added to active tests: New count==" 
                    + ActiveTests.Count.ToString());
            }

        }
        DirectoryInfo StartTest_BuildResultsPath(DefTestCase oTest, int iLogIndent)
        {
            return (StartTest_BuildResultsPath(oTest, true, iLogIndent));
        }
        private DirectoryInfo StartTest_BuildResultsPath(DefTestCase oTest, bool bClearContents, int iLogIndent)
        {
            string sVal = ConfigurationManager.AppSettings["PostResults_RootPath"];
            DirectoryInfo dirTC = new DirectoryInfo(ConfigurationManager.AppSettings["PostResults_RootPath"].ToString());

            dirTC = dirTC.CreateSubdirectory(oTest.RunGuid);
            dirTC = dirTC.CreateSubdirectory(oTest.Guid);

            // clear any existing files
            if (bClearContents)
            {
                foreach (FileInfo f in dirTC.GetFiles("*.*"))
                {
                    try { f.Delete(); }
                    catch { }
                }
            }
            return (dirTC);
        }
        private DirectoryInfo BuildFailedPath(DefTestCase oTest, int iLogIndent)
        {
            string sVal = ConfigurationManager.AppSettings["PostResults_RootPath"];
            DirectoryInfo dirTC = new DirectoryInfo(ConfigurationManager.AppSettings["PostResults_RootPath"].ToString());

            dirTC = dirTC.CreateSubdirectory(oTest.RunGuid);
            dirTC = dirTC.CreateSubdirectory("FailedResults");
            dirTC = dirTC.CreateSubdirectory(oTest.Guid);
            dirTC = dirTC.CreateSubdirectory(DateTime.Now.ToString("yyyyMMdd-hhmmss"));

            return (dirTC);
        }
        private bool StartTest_WriteInputFile(DefTestCase oTest, DirectoryInfo dirTarget, int iLogIndent)
        {
            Logger.Log(iLogIndent, "RunsManager", "-Creating XML");
            XmlDocument oXmlDoc = new XmlDocument();
            oXmlDoc.AppendChild(oXmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null));

            XmlNode oNodeRoot = oXmlDoc.CreateElement("PhoenixATBTestRun");
            oXmlDoc.AppendChild(oNodeRoot);

            oNodeRoot.Attributes.Append(oXmlDoc.CreateAttribute("TestMachineDetails"));
            oNodeRoot.Attributes.Append(oXmlDoc.CreateAttribute("RunStartTime"));
            oNodeRoot.Attributes.Append(oXmlDoc.CreateAttribute("RunStartDate"));
            oNodeRoot.Attributes.Append(oXmlDoc.CreateAttribute("RunName"));
            oNodeRoot.Attributes.Append(oXmlDoc.CreateAttribute("IPAddress"));
            oNodeRoot.Attributes.Append(oXmlDoc.CreateAttribute("UNCPostPath"));
            oNodeRoot.Attributes.Append(oXmlDoc.CreateAttribute("RootPostPath"));
            oNodeRoot.Attributes.Append(oXmlDoc.CreateAttribute("RunInstanceID"));
            
            oNodeRoot.Attributes["RunName"].InnerText = ScheduledRuns[oTest.RunKey].Name;
            oNodeRoot.Attributes["RunInstanceID"].InnerText = oTest.RunGuid;
            oNodeRoot.Attributes["RunStartDate"].InnerText = DateTime.Now.ToString("yyyyMMdd");
            oNodeRoot.Attributes["RunStartTime"].InnerText = DateTime.Now.ToString("hhmmss");
            oNodeRoot.Attributes["UNCPostPath"].InnerText = dirTarget.ToString();
            {
                string sRootPath = ConfigurationManager.AppSettings["PostResults_RootPath"];
                sRootPath = dirTarget.ToString().Substring(sRootPath.Length);
                sRootPath = ConfigurationManager.AppSettings["PostResults_MacVMShareRoot"] + sRootPath;
                oNodeRoot.Attributes["RootPostPath"].InnerText = sRootPath.Replace("\\", "/");

            }
            oNodeRoot.Attributes["IPAddress"].InnerText = oTest.AssignedIp;
            oNodeRoot.Attributes["TestMachineDetails"].InnerText = oTest.TestMachineUsed;

            Dictionary<string, string> dictBaseStateParams;
            {
                BaseStateClass oBaseState = GetBaseState(oTest, iLogIndent + 1);
                if (oBaseState == null)
                {
                    Logger.Log(iLogIndent, "RunsManager", "*Problem getting base state details from DB for DefRunDataID " + oTest.DefRunDataID.ToString());
                    return (false);
                }
                XmlNode oNodeBaseState = oXmlDoc.CreateElement("BaseState");
                oNodeRoot.AppendChild(oNodeBaseState);
                oNodeBaseState.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                oNodeBaseState.Attributes["Name"].InnerText = oBaseState.Name;

                foreach (string sKey in oBaseState.Params.Keys)
                {
                    XmlNode oNodeBaseStateParam = oXmlDoc.CreateElement("Parameter");
                    oNodeBaseState.AppendChild(oNodeBaseStateParam);
                    oNodeBaseStateParam.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                    oNodeBaseStateParam.Attributes["Name"].InnerText = sKey;
                    oNodeBaseStateParam.InnerText = oBaseState.Params[sKey];
                }
                dictBaseStateParams = oBaseState.Params;
            }

            List<DefTestCase> listTestCases = new List<DefTestCase>();
            if ((oTest.ExecutionOrder == enumExecutionOrder.Sequential
                && oTest.MachineOp == enumMachineOp.RestoreInitiallyForSet))
            {
                // build sequence
                foreach (DefTestCase oTestInSeq in ActiveSequentialTestSets[oTest.TestSetKey].TestCaseSeq.Values)
                    listTestCases.Add(oTestInSeq);
            }
            else
            {
                listTestCases.Add(oTest);
            }

            XmlNode oNodeTestCases = oXmlDoc.CreateElement("TestCases");
            oNodeTestCases.Attributes.Append(oXmlDoc.CreateAttribute("Count"));
            oNodeTestCases.Attributes["Count"].InnerText = listTestCases.Count.ToString("D3");
            oNodeRoot.AppendChild(oNodeTestCases);

            int iTestSequence = 0;
            foreach (DefTestCase oTestInSeq in listTestCases)
            {
                iTestSequence++;

                XmlNode oNodeTestCase = oXmlDoc.CreateElement("TestCase");
                oNodeTestCases.AppendChild(oNodeTestCase);

                oNodeTestCase.Attributes.Append(oXmlDoc.CreateAttribute("Sequence"));
                oNodeTestCase.Attributes.Append(oXmlDoc.CreateAttribute("Revision"));
                oNodeTestCase.Attributes.Append(oXmlDoc.CreateAttribute("QCID"));
                oNodeTestCase.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                oNodeTestCase.Attributes.Append(oXmlDoc.CreateAttribute("TCRunInstanceID"));
                oNodeTestCase.Attributes.Append(oXmlDoc.CreateAttribute("Key"));
                oNodeTestCase.Attributes["Key"].InnerText = oTestInSeq.Key.ToString("D8");
                oNodeTestCase.Attributes["TCRunInstanceID"].InnerText = oTestInSeq.Guid;
                oNodeTestCase.Attributes["Name"].InnerText = oTestInSeq.TestCaseName;
                oNodeTestCase.Attributes["QCID"].InnerText = oTestInSeq.TestQCID;
                oNodeTestCase.Attributes["Revision"].InnerText = oTestInSeq.TestCaseRevision;
                oNodeTestCase.Attributes["Sequence"].InnerText = iTestSequence.ToString("D3");

                DefTestDataSetRow oTestDataSetRow;
                while(true)
                {
                    oTestDataSetRow = GetTestDataSetRow(oTestInSeq, iLogIndent);

                    XmlNode oNodeDataSet = oXmlDoc.CreateElement("TestData");
                    oNodeTestCase.AppendChild(oNodeDataSet);

                    if (oTestDataSetRow == null)
                    {
                        oNodeDataSet.InnerText = " ";
                        break;
                    }

                    oNodeDataSet.Attributes.Append(oXmlDoc.CreateAttribute("Row"));
                    oNodeDataSet.Attributes.Append(oXmlDoc.CreateAttribute("Revision"));
                    oNodeDataSet.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                    oNodeDataSet.Attributes["Name"].InnerText = oTestDataSetRow.Name;
                    oNodeDataSet.Attributes["Revision"].InnerText = oTestDataSetRow.Revision.ToString();
                    oNodeDataSet.Attributes["Row"].InnerText = oTestDataSetRow.RowNumber.ToString();
                    oNodeDataSet.Attributes["Row"].InnerText += " of ";
                    oNodeDataSet.Attributes["Row"].InnerText += oTestDataSetRow.RowCount.ToString();

                    XmlNode oNodeDataSetColumns = oXmlDoc.CreateElement("Columns");
                    oNodeDataSetColumns.Attributes.Append(oXmlDoc.CreateAttribute("Count"));
                    oNodeDataSetColumns.Attributes["Count"].InnerText = oTestDataSetRow.Values.Count.ToString("D3");
                    oNodeDataSet.AppendChild(oNodeDataSetColumns);

                    foreach (string sKey in oTestDataSetRow.Values.Keys)
                    {
                        XmlNode oNodeDataSetColumn = oXmlDoc.CreateElement("Column");
                        oNodeDataSetColumns.AppendChild(oNodeDataSetColumn);
                        oNodeDataSetColumn.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                        oNodeDataSetColumn.Attributes["Name"].InnerText = sKey;
                        oNodeDataSetColumn.InnerText = oTestDataSetRow.Values[sKey];
                    }
                    break;
                }

                // Create Lists Element
                {
                    Dictionary<string, string> dictValuePairs = GetListValuesConcat(new List<string> { "Chrome-Modules", "Firefox-Modules", "Safari-Modules", "TestMachineGenericLogin" }, iLogIndent + 1);
                    if (dictValuePairs == null)
                    {
                        Logger.Log(iLogIndent, "RunsManager", "*Problem getting lists from DB");
                        return (false);
                    }

                    XmlNode oNodeLists = oXmlDoc.CreateElement("Lists");
                    oNodeLists.Attributes.Append(oXmlDoc.CreateAttribute("Count"));
                    oNodeLists.Attributes["Count"].InnerText = dictValuePairs.Count.ToString("D3");
                    oNodeTestCase.AppendChild(oNodeLists);

                    foreach (string sKey in dictValuePairs.Keys)
                    {
                        XmlNode oNodeList = oXmlDoc.CreateElement("List");
                        oNodeLists.AppendChild(oNodeList);
                        oNodeList.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                        oNodeList.Attributes["Name"].InnerText = sKey;
                        oNodeList.InnerText = dictValuePairs[sKey];
                    }
                }

                {
                    OrderedDictionary loTestSteps = GetTestSteps(oTestInSeq.DefTestCaseID, iLogIndent + 1);
                    if (loTestSteps == null)
                    {
                        Logger.Log(iLogIndent, "RunsManager", "*Problem getting test steps from DB for def test case ID " + oTestInSeq.DefTestCaseID.ToString());
                        return (false);
                    }

                    XmlNode oNodeTestSteps = oXmlDoc.CreateElement("TestSteps");
                    oNodeTestCase.AppendChild(oNodeTestSteps);

                    int iStepSequence = 0;
                    foreach (TestStepClass oTestStep in loTestSteps.Values)
                    {
                        iStepSequence++;
                        XmlNode oNodeTestStep = oXmlDoc.CreateElement("TestStep");
                        oNodeTestStep.Attributes.Append(oXmlDoc.CreateAttribute("LastStep"));
                        oNodeTestStep.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                        oNodeTestStep.Attributes.Append(oXmlDoc.CreateAttribute("Sequence"));
                        oNodeTestStep.Attributes.Append(oXmlDoc.CreateAttribute("Key"));
                        oNodeTestStep.Attributes["Key"].InnerText = oTestStep.Key.ToString("D8");
                        oNodeTestStep.Attributes["Sequence"].InnerText = iStepSequence.ToString("D3");
                        oNodeTestStep.Attributes["Name"].InnerText = oTestStep.Name;
                        oNodeTestStep.Attributes["LastStep"].InnerText = "0";

                        XmlNode oNodeTestStepActionWord = oXmlDoc.CreateElement("ActionWord");
                        oNodeTestStep.AppendChild(oNodeTestStepActionWord);
                        oNodeTestStepActionWord.Attributes.Append(oXmlDoc.CreateAttribute("Type"));
                        oNodeTestStepActionWord.Attributes["Type"].InnerText = oTestStep.Type;
                        oNodeTestStepActionWord.InnerText = oTestStep.Actionword;

                        XmlNode oNodeTestStepParams = oXmlDoc.CreateElement("Parameters");
                        oNodeTestStepParams.Attributes.Append(oXmlDoc.CreateAttribute("Count"));
                        oNodeTestStepParams.Attributes["Count"].InnerText = oTestStep.Params.Count.ToString();
                        oNodeTestStep.AppendChild(oNodeTestStepParams);

                        int iTestStepParamSequence = 0;
                        if (oTestStep.Params.Count > 0)
                        {
                            foreach (string sKey in oTestStep.Params.Keys)
                            {
                                iTestStepParamSequence++;
                                XmlNode oNodeTestStepParam = oXmlDoc.CreateElement("Parameter");
                                oNodeTestStepParams.AppendChild(oNodeTestStepParam);
                                oNodeTestStepParam.Attributes.Append(oXmlDoc.CreateAttribute("Sequence"));
                                oNodeTestStepParam.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                                oNodeTestStepParam.Attributes["Name"].InnerText = sKey;
                                oNodeTestStepParam.Attributes["Sequence"].InnerText = iTestStepParamSequence.ToString("D3");
                                if (null == oTestDataSetRow)
                                    oNodeTestStepParam.InnerText = HandleTestStepParamValue(oTestStep.Params[sKey], dictBaseStateParams, null, iLogIndent + 1);
                                else
                                    oNodeTestStepParam.InnerText = HandleTestStepParamValue(oTestStep.Params[sKey], dictBaseStateParams, oTestDataSetRow.Values, iLogIndent + 1);
                            }
                        }
                        oNodeTestSteps.AppendChild(oNodeTestStep);
                    }
                    // final step, we don't process this, just to signal to engine that we are done
                    {
                        iStepSequence++;
                        XmlNode oNodeTestStep = oXmlDoc.CreateElement("TestStep");
                        oNodeTestSteps.AppendChild(oNodeTestStep);
                        oNodeTestStep.Attributes.Append(oXmlDoc.CreateAttribute("LastStep"));
                        oNodeTestStep.Attributes.Append(oXmlDoc.CreateAttribute("Name"));
                        oNodeTestStep.Attributes.Append(oXmlDoc.CreateAttribute("Sequence"));
                        oNodeTestStep.Attributes.Append(oXmlDoc.CreateAttribute("Key"));
                        oNodeTestStep.Attributes["Key"].InnerText = "99999999";
                        oNodeTestStep.Attributes["Name"].InnerText = "*EndOfTestcase";
                        oNodeTestStep.Attributes["Sequence"].InnerText = iStepSequence.ToString("D3");
                        oNodeTestStep.Attributes["LastStep"].InnerText = "1";
                    }
                    oNodeTestSteps.Attributes.Append(oXmlDoc.CreateAttribute("Count"));
                    oNodeTestSteps.Attributes["Count"].InnerText = Convert.ToString(iStepSequence);
                }
            }

            string sFilename = ConfigurationManager.AppSettings["PostResults_InputFileName"];
            oXmlDoc.Save(dirTarget.ToString() + "\\" + sFilename + ".xml");
            Logger.Log(iLogIndent, "RunsManager", "-Posted XML to path:" + dirTarget.ToString());
            Logger.Log(iLogIndent, "RunsManager", "-Filename:" + sFilename);

            return (true);

        }
        private BaseStateClass GetBaseState(DefTestCase oTest, int iLogIndent)
        {
            BaseStateClass oBaseState;
            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                DataTable dtList;
                dtList = objATBDB.GetParamListForBaseState(oTest.TestSetKey, oTest.DefRunDataID);
                if (dtList.Rows.Count == 0)
                    return (null);
                oBaseState = new BaseStateClass(dtList.Rows[0]["Name"].ToString());

                for (int iIndex = 0; iIndex < dtList.Rows.Count; iIndex++)
                {
                    oBaseState.Params.Add
                        (
                            dtList.Rows[iIndex]["ParamName"].ToString(),
                            dtList.Rows[iIndex]["ParamValue"].ToString()
                        );
                }

                // Now we iterate through and populate any "AUTO" parameters
                foreach( string sKey in oBaseState.Params.Keys.ToList<string>() )
                {
                    if(oBaseState.Params[sKey] == "AUTO")
                    {
                        switch( sKey )
                        {
                            case "BrowserInstaller":
                                // validate prereq
                                if (!oBaseState.Params.ContainsKey("BrowserName"))
                                {
                                    oBaseState.Params[sKey] = "AUTO not handled: BrowserName Param missing for " + sKey;
                                    continue;
                                }
                                if (!oBaseState.Params.ContainsKey("BrowserVersionType"))
                                {
                                    oBaseState.Params[sKey] = "AUTO not handled: BrowserVersionType Param missing for " + sKey;
                                    continue;
                                }
                                // lookup value
                                oBaseState.Params[sKey] = objATBDB.GetListValueForParam(
                                                            "Installer-"
                                                            + oBaseState.Params["BrowserName"] + "-"
                                                            + oBaseState.Params["BrowserVersionType"]
                                                        );
                                break;
                            case "NSMeterInstaller":
                                // validate prereq
                                if (!oBaseState.Params.ContainsKey("OSVendor"))
                                {
                                    oBaseState.Params[sKey] = "AUTO not handled: OSVendor Param missing for " + sKey;
                                    continue;
                                }
                                if (!oBaseState.Params.ContainsKey("NSMeterVersionType"))
                                {
                                    oBaseState.Params[sKey] = "AUTO not handled: NSMeterVersionType Param missing for " + sKey;
                                    continue;
                                }
                                // lookup value
                                oBaseState.Params[sKey] = objATBDB.GetListValueForParam(
                                                            "NSMI-"
                                                            + oBaseState.Params["OSVendor"] + "-"
                                                            + oBaseState.Params["NSMeterVersionType"]
                                                        );
                                break;
                            case "AdobeFlashInstaller":
                                // validate prereq
                                if (!oBaseState.Params.ContainsKey("AdobeFlashVersionType"))
                                {
                                    oBaseState.Params[sKey] = "AUTO not handled: AdobeFlashVersionType Param missing for " + sKey;
                                    continue;
                                }
                                // lookup value
                                oBaseState.Params[sKey] = objATBDB.GetListValueForParam(
                                                            "Installer-AdobeFlash-"
                                                            + oBaseState.Params["AdobeFlashVersionType"]
                                                        );
                                break;
                            case "MSSilverlightInstaller":
                                // validate prereq
                                if (!oBaseState.Params.ContainsKey("MSSilverlightVersionType"))
                                {
                                    oBaseState.Params[sKey] = "AUTO not handled: MSSilverlightVersionType Param missing for " + sKey;
                                    continue;
                                }
                                // lookup value
                                oBaseState.Params[sKey] = objATBDB.GetListValueForParam(
                                                            "Installer-MSSilverlight-"
                                                            + oBaseState.Params["MSSilverlightVersionType"]
                                                        );
                                break;
                            default:
                                continue;
                        }
                    }
                }
            }
            return (oBaseState);
        }
        private DefTestDataSetRow GetTestDataSetRow(DefTestCase oTest, int iLogIndent)
        {
            if (oTest.TestDataSetDataKey == -1)
                return null;

            DefTestDataSetRow oTestDataSetRow;

            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                DataTable dtList;
                dtList = objATBDB.GetTestDataSetRow(oTest.TestDataSetDataKey);
                if (dtList.Rows.Count == 0)
                    return (null);
                oTestDataSetRow = new DefTestDataSetRow()
                    {
                        Key = int.Parse(dtList.Rows[0]["ID"].ToString()),
                        Name = dtList.Rows[0]["Name"].ToString(),
                        Revision = int.Parse(dtList.Rows[0]["Revision"].ToString()),
                        Description = dtList.Rows[0]["Description"].ToString(),
                        RowNumber = int.Parse(dtList.Rows[0]["RowNumber"].ToString()),
                        RowCount = int.Parse(dtList.Rows[0]["RowCount"].ToString())
                    };
                
                for (int iIndex = 1; iIndex < 10; iIndex++)
                {
                    string sDataColName = dtList.Rows[0]["DataPointName" + iIndex.ToString("D2")].ToString().Trim();
                    if (string.IsNullOrEmpty(sDataColName))
                        continue;
                    if (sDataColName.ToLower().Equals("null"))
                        continue;
                    string sDataColData = dtList.Rows[0]["DataPointData" + iIndex.ToString("D2")].ToString().Trim();
                    if (string.IsNullOrEmpty(sDataColData))
                        continue;
                    if (sDataColData.ToLower().Equals("null"))
                        continue;
                    oTestDataSetRow.Values.Add(
                            sDataColName,
                            sDataColData
                    );
                }
            }
            return (oTestDataSetRow);
        }

        private OrderedDictionary GetTestSteps(int iDefTestCaseID, int iLogIndent)
        {
            OrderedDictionary loTestSteps;
            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                DataTable dtList;
                dtList = objATBDB.GetTestSteps(iDefTestCaseID);
                if (dtList.Rows.Count == 0)
                    return (null);

                loTestSteps = new OrderedDictionary();


                for (int iIndex = 0; iIndex < dtList.Rows.Count; iIndex++)
                {
                    int iKey = int.Parse(dtList.Rows[iIndex]["Key"].ToString());
                    TestStepClass oTestStep = new TestStepClass
                    (
                        iKey,
                        dtList.Rows[iIndex]["Name"].ToString(),
                        dtList.Rows[iIndex]["Actionword"].ToString(),
                        dtList.Rows[iIndex]["Type"].ToString()
                    );
                    loTestSteps.Add(oTestStep.Key.ToString("D8"), oTestStep);

                    while (true)
                    {
                        if (dtList.Rows[iIndex]["ParamName"].ToString() != "")
                            oTestStep.Params.Add
                            (
                                dtList.Rows[iIndex]["ParamName"].ToString(),
                                dtList.Rows[iIndex]["ParamValue"].ToString()
                            );
                        if (iIndex + 1 == dtList.Rows.Count)
                            break;
                        if (iKey != int.Parse(dtList.Rows[iIndex + 1]["Key"].ToString()))
                            break;
                        iIndex++;
                    }
                }
            }
            return (loTestSteps);
        }
        private string HandleTestStepParamValue(string sValue, Dictionary<string, string> lsParams, Dictionary<string, string> lsDataSet, int iLogIndent)
        {
            if (lsParams != null && sValue.Contains("[["))
            {
                foreach (string sKey in lsParams.Keys)
                {
                    sValue = sValue.Replace("[[" + sKey + "]]", lsParams[sKey]);
                }
            }
            if (lsDataSet != null && sValue.Contains("{{"))
            {
                foreach (string sKey in lsDataSet.Keys)
                {
                    sValue = sValue.Replace("{{" + sKey + "}}", lsDataSet[sKey]);
                }
            }
            return (sValue);
        }
        private Dictionary<string, string> GetListValuesConcat(List<string> lsListNames, int iLogIndent)
        {
            Dictionary<string, string> dictValuePairs = new Dictionary<string, string>();
            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                DataTable dtValue;

                foreach (string sListName in lsListNames)
                {
                    dtValue = objATBDB.GetListValuesConcat(sListName);
                    if (dtValue.Rows.Count == 0)
                        return (null);
                    dictValuePairs.Add(sListName, dtValue.Rows[0][0].ToString());
                }
            }
            return (dictValuePairs);
        }
        private void StartTest_LaunchClient(DefTestCase oTest, int iLogIndent)
        {
            string sClientJar = ConfigurationManager.AppSettings["ATBClientJar"];
            string sJVM = ConfigurationManager.AppSettings["JVM"];
            string sJVM_Params = ConfigurationManager.AppSettings["JVM_Params"];
            string sWorkingFolder = ConfigurationManager.AppSettings["WorkingRootFolder"];
            string sTestCaseFilename = ConfigurationManager.AppSettings["PostResults_InputFileName"];

            Logger.Log(iLogIndent, "RunsManager", "-JVM:" + sJVM);
            Logger.Log(iLogIndent, "RunsManager", "-JVM Args:" + sJVM_Params);
            Logger.Log(iLogIndent, "RunsManager", "-ClientJar:" + sClientJar);

            ProcessStartInfo startInfo = new ProcessStartInfo();

            startInfo.FileName = sJVM;
            startInfo.Arguments = sJVM_Params + " " + sClientJar + " " + oTest.ResultsPath + "\\" + sTestCaseFilename + ".xml";
            startInfo.WorkingDirectory = sWorkingFolder;
            startInfo.WindowStyle = ProcessWindowStyle.Minimized;

            oTest.ClientPid = Process.Start(startInfo);
            oTest.StartTime = DateTime.Now;

            SaveProcessInfoForActiveTest(oTest, iLogIndent + 1);
        }
        private void SaveProcessInfoForActiveTest(DefTestCase oTest, int iLogIndent)
        {
            string sATBProcInfoFile = ConfigurationManager.AppSettings["WorkingRootFolder"];
            sATBProcInfoFile = sATBProcInfoFile + "\\" + "ATBProcInfo.xml";
            XmlDocument oXmlDoc = new XmlDocument();
            XmlNode oNodeRoot;
            if (File.Exists(sATBProcInfoFile))
            {
                oXmlDoc.Load(sATBProcInfoFile);
                oNodeRoot = oXmlDoc.DocumentElement.SelectSingleNode("/PhoenixATBProcInfo");
            }
            else
            {
                oXmlDoc.AppendChild(oXmlDoc.CreateXmlDeclaration("1.0", "UTF-8", null));
                oNodeRoot = oXmlDoc.CreateElement("PhoenixATBProcInfo");
                oXmlDoc.AppendChild(oNodeRoot);
            }

            // check if this is a sequence
            bool bSequence = (oTest.ExecutionOrder == enumExecutionOrder.Sequential
                && oTest.MachineOp == enumMachineOp.RestoreInitiallyForSet);
            List<DefTestCase> listTestCases = new List<DefTestCase>();
            if (bSequence)
            {
                // build sequence
                foreach (DefTestCase oTestInSeq in ActiveSequentialTestSets[oTest.TestSetKey].TestCaseSeq.Values)
                    listTestCases.Add(oTestInSeq);
                ActiveSequentialTestSets[oTest.TestSetKey].ClientPid = oTest.ClientPid;
            }
            else
            {
                listTestCases.Add(oTest);
            }

            foreach (DefTestCase oTestInSeq in listTestCases)
            {
                oTestInSeq.StartTime = oTest.StartTime;
                oTestInSeq.ClientPid = oTest.ClientPid;
                oTestInSeq.AsssignedTestMachine = oTest.AsssignedTestMachine;
                oTestInSeq.TestMachineUsed = oTest.TestMachineUsed;
                oTestInSeq.ResultsPath = oTest.ResultsPath;

                XmlNode oNodeProc = oXmlDoc.CreateElement("TestClientProcess");
                oNodeRoot.AppendChild(oNodeProc);
                oNodeProc.Attributes.Append(oXmlDoc.CreateAttribute("TestID"));
                oNodeProc.Attributes.Append(oXmlDoc.CreateAttribute("TestName"));
                oNodeProc.Attributes.Append(oXmlDoc.CreateAttribute("AssignedTestMachineID"));
                oNodeProc.Attributes.Append(oXmlDoc.CreateAttribute("ProcessID"));
                oNodeProc.Attributes.Append(oXmlDoc.CreateAttribute("StartTime"));
                oNodeProc.Attributes.Append(oXmlDoc.CreateAttribute("TestMachineUsed"));
                oNodeProc.Attributes.Append(oXmlDoc.CreateAttribute("ResultsPath"));
                oNodeProc.Attributes["TestID"].InnerText = oTestInSeq.Key.ToString();
                oNodeProc.Attributes["TestName"].InnerText = oTestInSeq.TestCaseName;
                oNodeProc.Attributes["AssignedTestMachineID"].InnerText = oTestInSeq.AsssignedTestMachine.ToString();
                oNodeProc.Attributes["ProcessID"].InnerText = oTestInSeq.ClientPid.Id.ToString();
                oNodeProc.Attributes["StartTime"].InnerText = oTestInSeq.StartTime.ToString();
                oNodeProc.Attributes["TestMachineUsed"].InnerText = oTestInSeq.TestMachineUsed;
                oNodeProc.Attributes["ResultsPath"].InnerText = oTestInSeq.ResultsPath;
            }            
            oXmlDoc.Save(sATBProcInfoFile);
        }
        private bool DeleteProcessInfoForTest(DefTestCase oTest, int iLogIndent)
        {
            string sATBProcInfoFile = ConfigurationManager.AppSettings["WorkingRootFolder"];
            sATBProcInfoFile = sATBProcInfoFile + "\\" + "ATBProcInfo.xml";
            XmlDocument oXmlDoc = new XmlDocument();
            if (File.Exists(sATBProcInfoFile))
                oXmlDoc.Load(sATBProcInfoFile);
            else
                return (false);

            XmlNode oXmlNode = oXmlDoc.DocumentElement.SelectSingleNode("/PhoenixATBProcInfo");

            foreach (XmlNode oNodeProc in oXmlNode.ChildNodes)
            {
                if (int.Parse(oNodeProc.Attributes["TestID"].InnerText) == oTest.Key)
                {
                    oXmlNode.RemoveChild(oNodeProc);
                    oXmlDoc.Save(sATBProcInfoFile);
                    return (true);
                }
            }

            return (false);
        }
        private bool GetActiveTestDetails(DefTestCase oTest, int iLogIndent)
        {
            string sATBProcInfoFile = ConfigurationManager.AppSettings["WorkingRootFolder"];
            sATBProcInfoFile = sATBProcInfoFile + "\\Prior_" + "ATBProcInfo.xml";
            XmlDocument oXmlDoc = new XmlDocument();
            if (File.Exists(sATBProcInfoFile))
                oXmlDoc.Load(sATBProcInfoFile);
            else
                return (false);

            XmlNode oXmlNode = oXmlDoc.DocumentElement.SelectSingleNode("/PhoenixATBProcInfo");
            if (oXmlNode == null)
                return (false);

            foreach (XmlNode oNodeProc in oXmlNode.ChildNodes)
            {
                if (int.Parse(oNodeProc.Attributes["TestID"].InnerText) == oTest.Key)
                {
                    oTest.TestMachineUsed = oNodeProc.Attributes["TestMachineUsed"].InnerText;
                    oTest.ResultsPath = oNodeProc.Attributes["ResultsPath"].InnerText;
                    Process proc;
                    try
                    {
                        
                        string sJavaProc = ConfigurationManager.AppSettings["JVM_Proc"];
                        proc = Process.GetProcessById(int.Parse(oNodeProc.Attributes["ProcessID"].InnerText));
                        if (proc.ProcessName.ToLower() == sJavaProc)
                        {
                            oTest.ClientPid = proc;
                            oTest.AsssignedTestMachine = int.Parse(oNodeProc.Attributes["AssignedTestMachineID"].InnerText);
                            oTest.StartTime = DateTime.Parse(oNodeProc.Attributes["StartTime"].InnerText);

                            TestMachine oTestMachine = TestMachineManager.TestMachines[oTest.AsssignedTestMachine];
                            oTestMachine.InUse = true;
                            if(oTestMachine.IsVirtal)
                                TestMachineManager.VirtualServers[oTestMachine.VirtualServerHost].ActiveConnections++;
                            return (true);
                        }
                    }
                    catch
                    {
                    }
                }
            }

            return (false);
        }
        private void ResetTestProcInfoFile(int iLogIndent)
        {
            string sATBProcInfoFile = ConfigurationManager.AppSettings["WorkingRootFolder"];

            if (File.Exists(sATBProcInfoFile + "\\Prior_" + "ATBProcInfo.xml"))
                File.Delete(sATBProcInfoFile + "\\Prior_" + "ATBProcInfo.xml");

            if (File.Exists(sATBProcInfoFile + "\\" + "ATBProcInfo.xml"))
                File.Move(sATBProcInfoFile + "\\" + "ATBProcInfo.xml", sATBProcInfoFile + "\\Prior_" + "ATBProcInfo.xml");
        }
        private bool CheckRunningTest(DefTestCase oTest, int iLogIndent)
        {
            if (!oTest.InProgress)
                return false;
            if (oTest.Completed)
                return false;
            if(ActiveSequentialTestSets.Keys.Contains(oTest.TestSetKey))
                Logger.Log(iLogIndent++, "RunsManager", "-Checking running test: Key:" + oTest.Key.ToString() 
                                                        + " " + oTest.TestCaseName
                                                        + "; Seq:" + ActiveSequentialTestSets[oTest.TestSetKey].TestSetKey.ToString());
            else
                Logger.Log(iLogIndent++, "RunsManager", "-Checking running test: key:" + oTest.Key.ToString()
                                                        + "; Name:" + oTest.TestCaseName);

            string sStatusFilename = ConfigurationManager.AppSettings["PostResults_StatusFileName"] + "_" + oTest.Key.ToString("D8") + ".xml";
            if (string.IsNullOrEmpty(oTest.ResultsPath))
                oTest.ResultsPath = StartTest_BuildResultsPath(oTest, false, iLogIndent + 1).ToString();
            sStatusFilename = oTest.ResultsPath + "\\" + sStatusFilename;

            bool bTestComplete = false;
            bool bProgramFailure = false;
            bool bResetTest = false;

            // first check the status*.xml file associated with the test case
            try
            {
                // first check status filename
                //Logger.Log(iLogIndent, "RunsManager", "-Checking status file");
                if (File.Exists(sStatusFilename))
                {
                    //Logger.Log(iLogIndent, "RunsManager", "-Status file exists");
                    XmlDocument oXmlDoc = new XmlDocument();
                    oXmlDoc.Load(sStatusFilename);

                    XmlNode oXmlNode = oXmlDoc.DocumentElement.SelectSingleNode("/ATBSTATUS/COMPLETE/STATE");
                    if (oXmlNode != null && (oXmlNode.InnerText == "Finished" || oXmlNode.InnerText == "Failed" || oXmlNode.InnerText == "Program Failure"))
                    {
                        //Logger.Log(iLogIndent, "RunsManager", "-COMPLETE node is present");
                        //Logger.Log(iLogIndent, "RunsManager", "-COMPLETE==" + oXmlNode.InnerText);
                        //Logger.Log(iLogIndent, "RunsManager", "-Checking for test results file");
                        string sResultsFilename = ConfigurationManager.AppSettings["PostResults_ResultsFileName"] + "_" + oTest.Key.ToString("D8") + ".xml";
                        sResultsFilename = oTest.ResultsPath + "\\" + sResultsFilename;
                        if (File.Exists(sResultsFilename))
                        {
                            Logger.Log(iLogIndent, "RunsManager", "-Test results file, test complete");
                            bTestComplete = true;
                            if (oXmlNode.InnerText == "Program Failure")
                                bProgramFailure = true;
                        }
                    }
                    else
                    {
                        // update last update time
                        DateTime dtLastUpdate = File.GetLastWriteTime(sStatusFilename);
                        if(dtLastUpdate > oTest.StartTime)
                        {
                            oTest.StartTime = dtLastUpdate;
                            Logger.Log(iLogIndent, "RunsManager", "-Updated start time to last file write time of " + dtLastUpdate.ToString());
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Logger.Log(iLogIndent, "RunsManager", "*Error reading Status file: " + ex.Message);
            }
            // no luck with status, check the process ID
            if (!bTestComplete)
            {
                // Checking for active process
                //Logger.Log(iLogIndent, "RunsManager", "-Checking for active PID and test results");
                if (oTest.ClientPid == null)
                {
                    Logger.Log(iLogIndent, "RunsManager", "-PID not assigned, try to get it from the last run");
                    if (!GetActiveTestDetails(oTest, iLogIndent + 1))
                    {
                        Logger.Log(iLogIndent, "RunsManager", "-Unable to get from last run");
                        if (oTest.StartTime == DateTime.MinValue)
                            oTest.StartTime = DateTime.Now;
                    }
                    else
                    {
                        Logger.Log(iLogIndent, "RunsManager", "-Found valid PID from last run");
                    }
                }
                // Either PID is NULL or process has exited without providing a status file
                if(oTest.ClientPid == null || oTest.ClientPid.HasExited)
                {
                    if (oTest.ClientPid != null)
                        Logger.Log(iLogIndent, "RunsManager", "-Client process has exited");
                    Logger.Log(iLogIndent, "RunsManager", "-Checking for test results file");
                    string sResultsFilename = ConfigurationManager.AppSettings["PostResults_ResultsFileName"] + "_" + oTest.Key.ToString("D8") + ".xml";
                    sResultsFilename = oTest.ResultsPath + "\\" + sResultsFilename;
                    if (File.Exists(sResultsFilename))
                    {
                        Logger.Log(iLogIndent, "RunsManager", "-Test results file, test complete");
                        bTestComplete = true;
                    }
                    else
                    {
                        Logger.Log(iLogIndent, "RunsManager", "-Process not active and test results not found, resetting test");
                        ResetRunningTest(oTest, iLogIndent + 1);
                        bTestComplete = true;
                        bProgramFailure = true;
                    }
                }
                //else
                    //Logger.Log(iLogIndent, "RunsManager", "-Client process PID still active");
            }
            // no luck with PID, check for the results file
            if (!bTestComplete)
            {
                string sResultsFilename = ConfigurationManager.AppSettings["PostResults_ResultsFileName"] + "_" + oTest.Key.ToString("D8") + ".xml";
                sResultsFilename = oTest.ResultsPath + "\\" + sResultsFilename;
                if (File.Exists(sResultsFilename))
                {
                    Logger.Log(iLogIndent, "RunsManager", "-Test results file, test appears to be complete");
                    bTestComplete = true;
                }
            }
            if (!bTestComplete)
            {
                // check stale time
                //Logger.Log(iLogIndent, "RunsManager", "-Checking run time");
                int iMaxWaitTime = oTest.MaxExecutionTimeMins;
                if(ActiveSequentialTestSets.ContainsKey(oTest.TestSetKey))
                    iMaxWaitTime = ActiveSequentialTestSets[oTest.TestSetKey].MaximumExecutionTimeMins;
                TimeSpan tsRunTime = DateTime.Now.Subtract(oTest.StartTime);
                double iRunTimeMins = Math.Floor(tsRunTime.TotalMinutes);
                int iRunTimeSecs = tsRunTime.Seconds;
                Logger.Log(iLogIndent, "RunsManager", "-Time since last status update (min:sec) " + iRunTimeMins.ToString("N0") + ":" + iRunTimeSecs.ToString("D2")
                                                    + "; Max " + iMaxWaitTime.ToString("N0") + ":00");
                if (iRunTimeMins > iMaxWaitTime)
                {
                    Logger.Log(iLogIndent, "RunsManager", "-Maximum run time exceeded; resetting test");
                    bTestComplete = true;
                    bProgramFailure = true;
                }
            }


            if (bTestComplete)
            {
                if (bProgramFailure)
                {
                    Logger.Log(iLogIndent, "RunsManager", "-Program failure detected - resetting");
                    TestsError++;
                    // capture failed files
                    DirectoryInfo dirSourcePath = new DirectoryInfo(oTest.ResultsPath);
                    DirectoryInfo dirTargetPath = BuildFailedPath(oTest, iLogIndent + 1);
                    // copy each result file
                    foreach (FileInfo fiFile in dirSourcePath.GetFiles())
                    {
                        fiFile.CopyTo(dirTargetPath.ToString() + "\\" + fiFile.Name);
                    }
                    Logger.Log(iLogIndent, "RunsManager", "-Results archived at: " + dirTargetPath.ToString());

                    // check for max tries
                    if (oTest.Tries >= 3)
                    {
                        Logger.Log(iLogIndent, "RunsManager", "-Test maximum tries of 3, we will not attempt again.");
                        PostErrorResult(oTest, "Test failed to execute after a maximum of 3 tries", iLogIndent);
                    }
                    else
                    {
                        ResetRunningTest(oTest, iLogIndent + 1);
                    }
                }
                else
                {
                    if (!bResetTest)
                    {
                        Logger.Log(iLogIndent, "RunsManager", "-Test completed");
                        Logger.Log(iLogIndent, "RunsManager", "-Updating database");
                        using (ATBSchemaDB objATBDB = new ATBSchemaDB())
                        {
                            if (string.IsNullOrEmpty(oTest.TestMachineUsed))
                                oTest.TestMachineUsed = "Unknown";
                            objATBDB.TestIndicateEnd(oTest.Key, oTest.RunKey, oTest.TestMachineUsed);
                        }
                        oTest.Completed = true;
                    }

                }
                if (ActiveSequentialTestSets.ContainsKey(oTest.TestSetKey))
                {
                    if (ActiveSequentialTestSets[oTest.TestSetKey].AllTestsCompleted())
                    {
                        Logger.Log(iLogIndent, "RunsManager", "-Sequence completed - setting test machine to available");
                        try
                        {
                            if (!oTest.ClientPid.HasExited)
                            {
                                Logger.Log(iLogIndent, "RunsManager", "-Warning - client process still active");
                                Logger.Log(iLogIndent, "RunsManager", "-Waiting 5 seconds before killing process");
                                Thread.Sleep(5000);
                                Logger.Log(iLogIndent, "RunsManager", "-Killing process ID " + oTest.ClientPid.Id.ToString());
                                oTest.ClientPid.Kill();
                            }
                        }
                        catch { }
                        TestMachineManager.SetUse(oTest.AsssignedTestMachine, oTest, false, iLogIndent + 1);
                    }
                    DeleteProcessInfoForTest(oTest, iLogIndent + 1);
                }
                else
                {
                    Logger.Log(iLogIndent, "RunsManager", "-Setting test machine to available");
                    try
                    {
                        if (!oTest.ClientPid.HasExited)
                        {
                            Logger.Log(iLogIndent, "RunsManager", "-Warning - client process still active");
                            Logger.Log(iLogIndent, "RunsManager", "-Waiting 5 seconds before killing process");
                            Thread.Sleep(5000);
                            Logger.Log(iLogIndent, "RunsManager", "-Killing process ID " + oTest.ClientPid.Id.ToString());
                            oTest.ClientPid.Kill();
                        }
                    }
                    catch { }
                    TestMachineManager.SetUse(oTest.AsssignedTestMachine, oTest, false, iLogIndent + 1);
                    DeleteProcessInfoForTest(oTest, iLogIndent + 1);
                }
                oTest.ClientPid = null;
            }
            return (bTestComplete);
        }
        public void ResetRunningTest(DefTestCase oTest, int iLogIndent)
        {
            oTest.InProgress = false;

            try
            {
                if (oTest.ClientPid != null)
                    oTest.ClientPid.Kill();
            }
            catch { }
            if (ActiveSequentialTestSets.ContainsKey(oTest.TestSetKey))
            {
                using (ATBSchemaDB objATBDB = new ATBSchemaDB())
                {
                    foreach (DefTestCase oTestInSeq in ActiveSequentialTestSets[oTest.TestSetKey].TestCaseSeq.Values)
                    {
                        if (!oTestInSeq.Failed)
                        {
                            objATBDB.TestReset(oTestInSeq.Key, oTestInSeq.RunKey);

                            oTestInSeq.InProgress = false;
                            oTestInSeq.Completed = false;
                            oTestInSeq.ClientPid = null;
                            ActiveTests.Remove(oTestInSeq.Key);
                        }
                    }
                }
                ActiveSequentialTestSets.Remove(oTest.TestSetKey);
            }
            else
            {
                oTest.ClientPid = null;
                using (ATBSchemaDB objATBDB = new ATBSchemaDB())
                {
                    objATBDB.TestReset(oTest.Key, oTest.RunKey);
                }
            }
        }
        void PostResult(DefTestCase oTest, int iLogIndent)
        {
            Logger.Log(iLogIndent++, "RunsManager", "-Posting results for test: Key==" 
                + oTest.Key.ToString() 
                + "; Name==" + oTest.TestCaseName
                );

            string sResultsFilename = ConfigurationManager.AppSettings["PostResults_ResultsFileName"] + "_" + oTest.Key.ToString("D8") + ".xml";
            string sInputFilename = ConfigurationManager.AppSettings["PostResults_InputFileName"] + ".xml";
            if (string.IsNullOrEmpty(oTest.ResultsPath))
                oTest.ResultsPath = StartTest_BuildResultsPath(oTest, false, iLogIndent + 1).ToString();

            if (!File.Exists(oTest.ResultsPath + "\\" + sResultsFilename))
            {
                string sErrorMessage = "Results file does not exist";
                Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                return;
            }

            Dictionary<int, DefTestStep> dictTestSteps = new Dictionary<int, DefTestStep>();

            // first build expected step results & params from input file
            XmlDocument XmlDoc = new XmlDocument();
            try
            {
                Logger.Log(iLogIndent, "RunsManager", "-Building sequence using input file");

                XmlDoc.Load(oTest.ResultsPath + "\\" + sInputFilename);
                XmlNode XmlNodeSteps = XmlDoc.SelectSingleNode("/PhoenixATBTestRun");
                if (XmlNodeSteps == null || !XmlNodeSteps.HasChildNodes)
                {
                    string sErrorMessage = "Input file invalid, cannot process PhoenixATBTestRun node";
                    Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                    PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                    return;
                }
                XmlNodeSteps = XmlNodeSteps.SelectSingleNode("TestCases");
                if (XmlNodeSteps == null || !XmlNodeSteps.HasChildNodes)
                {
                    string sErrorMessage = "Input file invalid, cannot process TestCases node";
                    Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                    PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                    return;
                }
                if (XmlNodeSteps == null || !XmlNodeSteps.HasChildNodes)
                {
                    string sErrorMessage = "Input file invalid, cannot process TestCase node";
                    Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                    PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                    return;
                }
                // find our test case node (among many?)
                if (XmlNodeSteps.ChildNodes.Count > 1)
                {
                    for (int iNodeIndex = 0; iNodeIndex < XmlNodeSteps.ChildNodes.Count; iNodeIndex++ )
                    {
                        if (int.Parse(XmlNodeSteps.ChildNodes[iNodeIndex].Attributes["Key"].InnerText.ToString()) == oTest.Key)
                        {
                            XmlNodeSteps = XmlNodeSteps.ChildNodes[iNodeIndex];
                            break;
                        }
                    }
                }
                else
                    XmlNodeSteps = XmlNodeSteps.SelectSingleNode("TestCase");
                XmlNodeSteps = XmlNodeSteps.SelectSingleNode("TestSteps");
                if (XmlNodeSteps == null || !XmlNodeSteps.HasChildNodes)
                {
                    string sErrorMessage = "Input file invalid, cannot process TestSteps node";
                    Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                    PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                    return;
                }

                foreach (XmlNode XmlNodeStep in XmlNodeSteps.ChildNodes)
                {
                    if (int.Parse(XmlNodeStep.Attributes["Key"].InnerText.ToString()) == 99999999)
                        continue;
                    DefTestStep oStep = new DefTestStep
                    {
                        DefTestStepID = int.Parse(XmlNodeStep.Attributes["Key"].InnerText),
                        StepName = XmlNodeStep.Attributes["Name"].InnerText,
                        ActionWordName = XmlNodeStep.SelectSingleNode("ActionWord").InnerText,
                        Result = "No Run",
                        ResultText = "",
                        Evidence = false
                    };

                    XmlNode XmlNodeStepParams = XmlNodeStep.SelectSingleNode("Parameters");
                    if (XmlNodeStepParams != null)
                    {
                        foreach (XmlNode XmlNodeStepParam in XmlNodeStepParams)
                        {
                            oStep.Parameters.Add(
                                new DefNameValuePair()
                                {
                                    Name = XmlNodeStepParam.Attributes["Name"].InnerText,
                                    Value = XmlNodeStepParam.InnerText
                                }
                            );
                        }
                    }

                    dictTestSteps.Add(oStep.DefTestStepID, oStep);
                }
                Logger.Log(iLogIndent+1, "RunsManager", "-Completed with steps count: "+dictTestSteps.Count.ToString());

            }
            catch(Exception ex)
            {
                string sErrorMessage = "Input file invalid, error parsing: " + ex.Message;
                Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                return;
            }

            XmlDoc.Load(oTest.ResultsPath + "\\" + sResultsFilename);
            try
            {
                Logger.Log(iLogIndent, "RunsManager", "-Completing steps using results file");

                XmlNode XmlNodeSteps = XmlDoc.SelectSingleNode("/ATBTestRunResults");
                if (XmlNodeSteps == null || !XmlNodeSteps.HasChildNodes)
                {
                    string sErrorMessage = "Results file invalid, cannot process ATBTestRunResults node";
                    Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                    PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                    return;
                }

                XmlNodeSteps = XmlNodeSteps.SelectSingleNode("TestCases");

                if (XmlNodeSteps == null || !XmlNodeSteps.HasChildNodes)
                {
                    string sErrorMessage = "Results file invalid, cannot process TestCases node";
                    Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                    PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                    return;
                }
                XmlNodeSteps = XmlNodeSteps.SelectSingleNode("TestCase");
                if (XmlNodeSteps == null || !XmlNodeSteps.HasChildNodes)
                {
                    string sErrorMessage = "Results file invalid, cannot process TestCase node";
                    Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                    PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                    return;
                }
                oTest.ExecutionResults = XmlNodeSteps.Attributes["Results"].InnerText;

                XmlNode XmlNodeEvidence = XmlNodeSteps.SelectSingleNode("Evidence");
                XmlNodeSteps = XmlNodeSteps.SelectSingleNode("TestSteps");
                if (XmlNodeSteps == null || !XmlNodeSteps.HasChildNodes)
                {
                    string sErrorMessage = "Results file invalid, cannot process TestSteps node";
                    Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                    PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                    return;
                }

                Logger.Log(iLogIndent + 1, "RunsManager", "-Processing steps from results file, count: " + XmlNodeSteps.ChildNodes.Count.ToString());
                foreach (XmlNode XmlNodeStep in XmlNodeSteps.ChildNodes)
                {
                    int iKey = int.Parse(XmlNodeStep.Attributes["Key"].InnerText);
                    if(dictTestSteps.ContainsKey(iKey))
                    {
                        DefTestStep oStep = dictTestSteps[iKey];

                        oStep.Result = XmlNodeStep.Attributes["Results"].InnerText;
                        if (XmlNodeStep.SelectSingleNode("ExpectedResultsText") == null)
                            oStep.ResultText = "";
                        else
                            oStep.ResultText = XmlNodeStep.SelectSingleNode("ExpectedResultsText").InnerText;
                        string sStepTime = XmlNodeStep.Attributes["StepTimeSecs"].InnerText;
                        int iStepTime = 0;
                        int.TryParse(sStepTime, out iStepTime);
                        oStep.RunTimeSecs = iStepTime;

                        // check evidence
                        XmlNode XmlNodeStepEvidence = XmlNodeStep.SelectSingleNode("Evidence");
                        if (XmlNodeStepEvidence == null)
                        {
                            Logger.Log(iLogIndent, "RunsManager", "-Evidence node not present for step");
                            oTest.Evidence = false;
                        }
                        else
                        {
                            if (XmlNodeStepEvidence.ChildNodes.Count == 0)
                            {
                                Logger.Log(iLogIndent, "RunsManager", "-Evidence node present but Proof node is not for step");
                                oTest.Evidence = false;
                            }
                            foreach (XmlNode XmlNodeProof in XmlNodeStepEvidence.ChildNodes)
                            {
                                string sFile = XmlNodeProof.InnerText.Trim();
                                if (string.IsNullOrEmpty(sFile))
                                {
                                    Logger.Log(iLogIndent, "RunsManager", "-XmlNodeProof node present but file reference is invalid for step");
                                    oTest.Evidence = false;
                                }
                                else
                                {
                                    if (File.Exists(sFile))
                                    {
                                        oStep.Evidence = true;
                                        oStep.Proof.Add(new TestEvidenceProof()
                                        {
                                            FileSpec = sFile,
                                            Name = XmlNodeProof.Attributes["Action"].InnerText,
                                            Type = XmlNodeProof.Attributes["Type"].InnerText,
                                            Description = XmlNodeProof.Attributes["Description"].InnerText
                                        }
                                        );
                                    }
                                    else
                                    {
                                        Logger.Log(iLogIndent, "RunsManager", "-XmlNodeProof node present but referenced file does not exist for step");
                                        oStep.Evidence = false;
                                    }
                                }
                            }

                        }

                    }
                }
                if (XmlNodeEvidence == null)
                {
                    Logger.Log(iLogIndent, "RunsManager", "-Evidence node not present");
                    oTest.Evidence = false;
                }
                else
                {
                    if (XmlNodeEvidence.ChildNodes.Count == 0)
                    {
                        Logger.Log(iLogIndent, "RunsManager", "-Evidence node present but Proof node is not");
                        oTest.Evidence = false;
                    }
                    foreach (XmlNode XmlNodeProof in XmlNodeEvidence.ChildNodes)
                    {
                        string sFile = XmlNodeProof.InnerText.Trim();
                        if (string.IsNullOrEmpty(sFile))
                        {
                            Logger.Log(iLogIndent, "RunsManager", "-XmlNodeProof node present but file reference is invalid");
                            oTest.Evidence = false;
                        }
                        else
                        {
                            if (File.Exists(sFile))
                            {
                                oTest.Evidence = true;
                                oTest.Proof.Add(new TestEvidenceProof()
                                {
                                    FileSpec = sFile,
                                    Name = XmlNodeProof.Attributes["Action"].InnerText,
                                    Type = XmlNodeProof.Attributes["Type"].InnerText,
                                    Description = XmlNodeProof.Attributes["Description"].InnerText
                                }
                                );
                            }
                            else
                            {
                                Logger.Log(iLogIndent, "RunsManager", "-XmlNodeProof node present but referenced file does not exist");
                                oTest.Evidence = false;
                            }
                        }
                    }

                }
            }
            catch (Exception ex)
            {
                string sErrorMessage = "Results file invalid, error parsing: " + ex.Message;
                Logger.Log(iLogIndent, "RunsManager", "*" + sErrorMessage);
                PostErrorResult(oTest, sErrorMessage, iLogIndent + 1);
                return;
            }

            // post results to the database
            Logger.Log(iLogIndent, "RunsManager", "-Posting results to database");
            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                Logger.Log(iLogIndent+1, "RunsManager", "-Posting steps and parameters");
                foreach (DefTestStep oTestStep in dictTestSteps.Values)
                {
                    // post the step
                    int iResTestStepID = objATBDB.TestPostResultStep
                        (
                            oTest.Key,
                            oTestStep.DefTestStepID,
                            oTestStep.StepName,
                            oTestStep.ActionWordName,
                            oTestStep.ResultText,
                            oTestStep.Result,
                            oTestStep.RunTimeSecs,
                            oTestStep.Evidence
                        );
                    // TODO: Handle step evidence
                    // post the step actual value pairs
                    int iSeqNo = 0;
                    foreach (DefNameValuePair oTestStepParam in oTestStep.Parameters)
                    {
                        objATBDB.TestPostResultStepParam
                            (
                                iResTestStepID,
                                ++iSeqNo,
                                oTestStepParam.Name,
                                oTestStepParam.Value
                            );
                    }
                    // If there is evidence, post it
                    if (oTestStep.Evidence)
                    {
                        Logger.Log(iLogIndent + 1, "RunsManager", "-Posting step level evidence files");
                        foreach (TestEvidenceProof oProof in oTestStep.Proof)
                        {
                            FileInfo file = new FileInfo(oProof.FileSpec);
                            objATBDB.TestPostResultEvidence
                                (
                                    iResTestStepID,
                                    @"ResTestStep",
                                    oProof.Name,
                                    oProof.Type,
                                    file.Name,
                                    oProof.Description,
                                    oProof.FileSpec
                                );
                        }
                    }

                }

                // If there is evidence, post it
                if (oTest.Evidence)
                {
                    Logger.Log(iLogIndent + 1, "RunsManager", "-Posting test level evidence files");
                    foreach (TestEvidenceProof oProof in oTest.Proof)
                    {
                        FileInfo file = new FileInfo(oProof.FileSpec);
                        objATBDB.TestPostResultEvidence
                            (
                                oTest.Key,
                                @"ResTestCase",
                                oProof.Name,
                                oProof.Type,
                                file.Name,
                                oProof.Description,
                                oProof.FileSpec
                            );
                    }
                }

                // Post TS and TR for later troubleshsooting
                if (File.Exists(oTest.ResultsPath + "\\" + sInputFilename))
                {
                    Logger.Log(iLogIndent + 1, "RunsManager", "-Posting test input file (" + sInputFilename + ")");
                    objATBDB.TestPostResultEvidence
                        (
                            oTest.Key,
                            @"ResTestCase",
                            @"Test Input XML",
                            @"Text",
                            sInputFilename,
                            @"Test engine input spec",
                            oTest.ResultsPath + "\\" + sInputFilename
                        );

                }
                if (File.Exists(oTest.ResultsPath + "\\" + sResultsFilename))
                {
                    Logger.Log(iLogIndent + 1, "RunsManager", "-Posting test output file (" + sResultsFilename + ")");
                    objATBDB.TestPostResultEvidence
                        (
                            oTest.Key,
                            @"ResTestCase",
                            @"Test Results XML",
                            @"Text",
                            sResultsFilename,
                            @"Test engine output results",
                            oTest.ResultsPath + "\\" + sResultsFilename
                        );
                }

                // finalize results
                Logger.Log(iLogIndent + 1, "RunsManager", "-Posting test case as complete to DB");
                objATBDB.TestPostResultComplete(oTest.Key, oTest.DefRunKey, oTest.ExecutionResults, oTest.Evidence);

                oTest.ResultsPosted = true;
            }

        }
        private void PostErrorResult(DefTestCase oTest, string sErrorMessage, int iLogIndent)
        {
            Logger.Log(iLogIndent++, "RunsManager", "-Posting test complete, but in error");

            // post results to the database
            Logger.Log(iLogIndent + 1, "RunsManager", "-Posting test case as error to DB");
            using (ATBSchemaDB objATBDB = new ATBSchemaDB())
            {
                objATBDB.TestPostResultError(oTest.Key, oTest.RunKey, sErrorMessage);
                oTest.InProgress = true;
                oTest.Completed = true;
                oTest.ResultsPosted = true;
                oTest.Failed = true;
            }
        }
    }
    public class Run
    {
        public int Key { get; set; }
        public string Name { get; set; }
        public DateTime Schedule { get; set; }
        public string Guid { get; set; }
        public bool InProgress { get; set; }

        public Run() { }
        public Run(int iKey, string sName, DateTime dtSchedule, string sGuid, bool bInProgress)
        {
            Key = iKey;
            Name = sName;
            Schedule = dtSchedule;
            Guid = sGuid;
            InProgress = bInProgress;
        }
    }
    public class TestSequence
    {
        public int TestSetKey { get; private set; }
        public int AssignedTestMachine { get; private set; }
        public OrderedDictionary TestCaseSeq {get; private set;}
        public int CurrentTestIndex { get; private set; }
        public int MaximumExecutionTimeMins { get; private set; }
        public Process ClientPid { get; set; }
        public DefTestCase CurrentTest
        {
            get
            {
                return (GetCurrentTest());
            }
        }
        public int Count
        {
            get
            {
                return (TestCaseSeq.Count);
            }
        }
        public TestSequence(DefTestCase oFirstTest, DefTestCase[] listTests)
        {
            // assign basic values
            TestSetKey = oFirstTest.TestSetKey;
            AssignedTestMachine = oFirstTest.AsssignedTestMachine;
            MaximumExecutionTimeMins = 0;
            TestCaseSeq = new OrderedDictionary();
            // iterate through test case collection and pick out the sequence
            foreach (DefTestCase oTest in listTests)
            {
                if (oTest.TestSetKey == TestSetKey)
                {
                    if (!oTest.Failed)
                    {
                        TestCaseSeq.Add(oTest.Key, oTest);
                        MaximumExecutionTimeMins += oTest.MaxExecutionTimeMins;
                    }
                }
            }
            CurrentTestIndex = 0;
        }
        public DefTestCase GetNextTest()
        {
            return ((DefTestCase)TestCaseSeq[++CurrentTestIndex]);
        }
        public bool IsLastTest()
        {
            return(CurrentTestIndex+1 == TestCaseSeq.Count);
        }
        public bool AllTestsCompleted()
        {
            foreach( DefTestCase oTest in TestCaseSeq.Values)
                if (!oTest.Completed)
                    return false;
            return true;
        }
        public DefTestCase GetCurrentTest()
        {
            return ((DefTestCase)TestCaseSeq[CurrentTestIndex]);
        }
    }
    public class DefTestStep
    {
        public int DefTestStepID { get; set; }
        public string StepName { get; set; }
        public string ActionWordName { get; set; }
        public string ResultText { get; set; }
        public string Result { get; set; }
        public int RunTimeSecs { get; set; }
        public bool Evidence { get; set; }

        private List<TestEvidenceProof> proof = new List<TestEvidenceProof>();
        public List<TestEvidenceProof> Proof
        {
            get
            {
                return (proof);
            }
        }
        private List<DefNameValuePair> parameters = new List<DefNameValuePair>();
        public List<DefNameValuePair> Parameters
        { get { return parameters; } }
    }
    public class DefNameValuePair
    {
        public string Name { get; set; }
        public string Value { get; set; }
    }
    public class DefTestDataSetRow
    {
        public int Key { get; set; }
        public string Name { get; set; }
        public int Revision { get; set; }
        public string Description { get; set; }
        public int RowNumber { get; set; }
        public int RowCount { get; set; }
        public Dictionary<string, string> Values;
        public DefTestDataSetRow()
        {
            Values = new Dictionary<string,string>();
        }
    }
    public enum enumExecutionOrder : int
    {
        None,
        Sequential
    }
    public enum enumMachineOp
    {
        None,
        RestorePerTest,
        RestoreInitiallyForSet,
        RestoreNone
    }
    public class DefTestCase
    {
        public int Key { get; set; }
        public string Guid { get; set; }
        public int RunKey { get; set; }
        public string RunGuid { get; set; }
        public int DefRunKey { get; set; }
        public int TestSetKey { get; set; }
        public string TestSetGuid { get; set; }
        public int DefTestCaseID { get; set; }
        public string TestCaseName { get; set; }
        public string TestQCID { get; set; }
        public string TestCaseRevision { get; set; }
        public double Order { get; set; }
        public int MaxExecutionTimeMins { get; set; }
        public List<int> TestMachineGroup { get; set; }
        public int DefRunDataID { get; set; }
        public int TestDataSetDataKey { get; set; }
        public bool InProgress { get; set; }
        public bool Completed { get; set; }
        public bool Failed { get; set; }
        public bool ResultsPosted { get; set; }
        public int AsssignedTestMachine { get; set; }
        public string TestMachineUsed { get; set; }
        public string ExecutionResults { get; set; }
        public string AssignedIp { get; set; }
        public string ResultsPath { get; set; }
        public Process ClientPid { get; set; }
        public DateTime StartTime { get; set; }
        private int tries = 0;
        public int Tries
        { get { return tries; } set { tries = value; } }
        public bool Evidence { get; set; }
        private List<TestEvidenceProof> proof = new List<TestEvidenceProof>();
        public List<TestEvidenceProof> Proof {
            get
            {
                return (proof);
            }
        }
        public enumMachineOp MachineOp { get; set; }
        public static enumMachineOp ParseMachineOp(string _value)
        {
            if (string.IsNullOrEmpty(_value))
                return(enumMachineOp.None);

            switch(_value)
            {
                case "Restore per test":
                    return(enumMachineOp.RestorePerTest);
                case "Restore initially for set":
                    return(enumMachineOp.RestoreInitiallyForSet);
                case "Restore none":
                    return(enumMachineOp.RestoreNone);
                default:
                    throw new Exception("Invalid value for MachineOp");
            }
        }
        public enumExecutionOrder ExecutionOrder { get; set; }
        public static enumExecutionOrder ParseExecutionOrder(string _value)
        {
            if (string.IsNullOrEmpty(_value))
                return (enumExecutionOrder.None);

            switch (_value)
            {
                case "None":
                    return (enumExecutionOrder.None);
                case "Sequential":
                    return (enumExecutionOrder.Sequential);
                default:
                    throw new Exception("Invalid value for ExecutionOrder");
            }
        }
    }
    public class BaseStateClass
    {
        public string Name;
        public Dictionary<string, string> Params;

        public BaseStateClass(string sName)
        {
            Name = sName;
            Params = new Dictionary<string, string>();
        }
    }
    public class TestStepClass
    {
        public int Key;
        public string Name;
        public string Actionword;
        public string Type;
        public Dictionary<string, string> Params;

        public TestStepClass(int iKey, string sName, string sActionword, string sType)
        {
            Key = iKey;
            Name = sName;
            Actionword = sActionword;
            Type = sType;
            Params = new Dictionary<string, string>();
        }
    }
    public class TestStepResultClass
    {
        public int DefTestStepID  { get; set; }
        public string ResultText { get; set; }
        public string Result { get; set; }
        public int RunTimeSecs { get; set; }
        public bool Evidence { get; set; }
        TestEvidenceProof Proof { get; set; }
    }
    public class TestEvidenceProof
    {
        public string Name { get; set; }
        public string Type { get; set; }
        public string Description { get; set; }
        public string FileSpec { get; set; }
    }
}
